package com.devops.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.devops.admin.mapper.DOSClusterNamespaceMapper;
import com.devops.admin.model.*;
import com.devops.admin.service.DOSClusterInfoService;
import com.devops.admin.service.DOSClusterNamespaceService;
import com.devops.admin.util.K8sClientUtil;
import com.devops.admin.vo.DOSClusterNamespaceVo;
import com.devops.admin.vo.DOSPageVo;
import io.fabric8.kubernetes.api.model.Namespace;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassNem DOSClusterNamespaceServiceImpl
 * @Description TODO
 * @Author heyabo
 * @Date 2022/3/18 11:33
 * @Version 1.0
 **/
@Service
public class DOSClusterNamespaceServiceImpl extends ServiceImpl<DOSClusterNamespaceMapper, DOSClusterNamespace> implements DOSClusterNamespaceService {
    @Autowired
    private DOSClusterInfoService dosClusterInfoService;

    @Override
    public TableResult<DOSClusterNamespace> getByClusterId(DOSClusterNamespace namespace, DOSPageVo pageVo) {
        Assert.isTrue(null!=namespace.getClusterId(),"集群id不能为空");
        getClient(namespace.getClusterId());
        Page<DOSClusterNamespace> page = new Page<>(pageVo.getPageNum(),pageVo.getPageSize());
        TableResult<DOSClusterNamespace> tableResult = new TableResult<>();
        List<DOSClusterNamespace> byClusterId = baseMapper.getByClusterId(page, namespace.getClusterId());
        Pagination p = Pagination.builder().pageNum(page.getCurrent()).pageSize(page.getSize()).total(page.getTotal()).build();
        tableResult.setList(byClusterId);
        tableResult.setPagination(p);
        return tableResult;
    }

    @Override
    public List<DOSClusterNamespace> getByClusterId(List<Integer> clusterIds) {
        return baseMapper.getByClusterIds(clusterIds);
    }

    @Override
    public List<DOSClusterNamespace> getByClusterId(int clusterId) {
        List<Integer> clusterIds = new ArrayList<>();
        clusterIds.add(clusterId);
        return baseMapper.getByClusterIds(clusterIds);
    }

    @Override
    public TableResult<DOSClusterNamespace> getNamespaceByName(DOSClusterNamespaceVo namespace, DOSPageVo pageVo) {
        Assert.isTrue(null!=namespace.getClusterId(),"集群id不能为空");
        Assert.isTrue(null!=namespace.getNamespace(),"命名空间名称不能为空");
        getClient(namespace.getClusterId());
        Page<DOSClusterNamespace> page = new Page<>(pageVo.getPageNum(),pageVo.getPageSize());
        TableResult<DOSClusterNamespace> tableResult = new TableResult<>();
        List<DOSClusterNamespace> spaceByName = baseMapper.getNamespaceByName(page, namespace.getClusterId(), namespace.getNamespace());
        Pagination p = Pagination.builder().pageNum(page.getCurrent()).pageSize(page.getSize()).total(page.getTotal()).build();
        tableResult.setList(spaceByName);
        tableResult.setPagination(p);
        return tableResult;
    }

    @Override
    public DOSClusterNamespace saveNamespace(DOSClusterNamespace namespace) {
        //校验命名空间的唯一性
        chekNamespace(namespace);
        KubernetesClient client = getClients(namespace.getClusterId());
        Namespace k8sNamespace = new Namespace();
        ObjectMeta objectMeta = new ObjectMeta();
        objectMeta.setName(namespace.getNamespace());
        k8sNamespace.setMetadata(objectMeta);
        try {
            client.namespaces().create(k8sNamespace);
        }catch (KubernetesClientException e){
            Assert.isTrue(true,e.getNamespace());
        }
        this.save(namespace);
        return namespace;
    }

    @Override
    public Boolean updateByNamespaceId(DOSClusterNamespace namespace) {
        //校验命名空间的唯一性
        chekNamespace(namespace);
        return this.updateById(namespace);
    }

    @Override
    public List<DOSClusterNamespace> getNamespaces(Integer clusterId) {

        LambdaQueryWrapper<DOSClusterNamespace> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DOSClusterNamespace::getClusterId,clusterId);
        return this.list(queryWrapper);
    }

    /**
     * @Author heyabo
     * @Description 获取client
     * @Date 16:37 2022/5/24
     * @Param [clusterId]
     * @return io.fabric8.kubernetes.client.KubernetesClient
     **/
    @Override
    public KubernetesClient getClients(int clusterId){
        LambdaQueryWrapper<DOSClusterInfo> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(DOSClusterInfo::getClusterId,clusterId);
        DOSClusterInfo clusterInfo = dosClusterInfoService.getOne(queryWrapper);

        return K8sClientUtil.getKubernetesClient(clusterInfo.getConfigPath(), clusterInfo.getConfigContent());
    }

    /**
     * @Author heyabo
     * @Description 校验集群命名空间的唯一性
     * @Date 14:33 2022/4/1
     * @Param [namespace]
     * @return void
     **/
    private void chekNamespace(DOSClusterNamespace paramNamespace) {
        long count = 0L;
        LambdaQueryWrapper<DOSClusterNamespace> queryWrapper = new LambdaQueryWrapper<>();
        if (paramNamespace.getId()!=null){
            List<DOSClusterNamespace> list = this.getByClusterId(paramNamespace.getClusterId());
            for (DOSClusterNamespace namespace : list) {
                if (namespace.getId().intValue()!=paramNamespace.getId().intValue() &&
                        namespace.getNamespace().equals(paramNamespace.getNamespace())){
                    count = 1;
                }
            }
        }else {
            queryWrapper.eq(DOSClusterNamespace::getNamespace, paramNamespace.getNamespace())
                    .eq(DOSClusterNamespace::getClusterId, paramNamespace.getClusterId());
            count = this.count(queryWrapper);
        }
        Assert.isTrue(count == 0,"同一集群内命名空间不能重复");
    }

    /**
     * @Author heyabo
     * @Description 获取clent
     * @Date 16:37 2022/5/24
     * @Param [clusterId]
     * @return io.fabric8.kubernetes.client.KubernetesClient
     **/
    private void getClient(int clusterId){
        LambdaQueryWrapper<DOSClusterInfo> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(DOSClusterInfo::getClusterId,clusterId);
        DOSClusterInfo clusterInfo = dosClusterInfoService.getOne(queryWrapper);
        KubernetesClient client = K8sClientUtil.getKubernetesClient(clusterInfo.getConfigPath(), clusterInfo.getConfigContent());
        List<String> collect = client.namespaces().list().getItems()
                .stream().filter(a->a.getStatus().getPhase().equals("Active"))
                .map(Namespace::getMetadata).map(ObjectMeta::getName).collect(Collectors.toList());
        List<DOSClusterNamespace> clusterNamespaces = this.getByClusterId(clusterId);
        List<DOSClusterNamespace> namespaces = new ArrayList<>();
        List<Integer> namespaceIds = new ArrayList<>();
        clusterNamespaces.forEach(space->{
            if (!collect.contains(space.getNamespace())){
                namespaceIds.add(space.getId());
            }else{
                collect.remove(space.getNamespace());
            }
        });
        if (CollectionUtil.isNotEmpty(collect)) {
            for (String s : collect) {
                DOSClusterNamespace namespace = new DOSClusterNamespace();
                namespace.setClusterId(clusterId);
                namespace.setNamespace(s);
                namespaces.add(namespace);
            }
            this.saveBatch(namespaces);
        }
        if (CollectionUtil.isNotEmpty(namespaceIds)){
            baseMapper.deleteBatchIds(namespaceIds);
        }

    }
}
